﻿
using EmperialApps.WeatherSpark.Data;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace EmperialApps.WeatherSpark.Agent {

    /// <summary>Renders the graph for the Windows Phone live tile.</summary>
    public partial class TileImage : TileImageBase {

        /// <summary>Initializes a new instance of the <see cref="TileImage"/> class.</summary>
        public TileImage( ) {
            InitializeComponent( );

            this.TileTitle.ClearValue( TextBlock.TextProperty );
            this.TileTitle.SetBinding( TextBlock.TextProperty, new Binding( "Title" ) { Source = this } );
            BindingOperations.SetBinding( this.BackgroundImage, ImageBrush.ImageSourceProperty, new Binding( "ImageSource" ) { Source = this } );
        }


        /// <inheritdoc/>
        public override void DisplayValues( Forecast forecast, Units units, ForecastDisplayMode mode ) {
            // Get time values for current mode.
            DateTimeOffset now = DateTimeOffset.UtcNow.ToOffset( forecast.Start.Offset );
            DateTimeOffset date = now.GetDateOffset( );
            DateTimeOffset begin = mode != ForecastDisplayMode.Hour ? date : date.AddHours( now.Hour - ConvertValue.HoursPerDay / 3 );
            double hourOffset = 1 + (int)now.HoursFrom( forecast.Start );

            // Get temperature and setup time scale.
            forecast.GetTemperatureValues( units, ref this._temperature );
            double currentTemperature = this._temperature.GetInterpolatedValue( hourOffset, ConvertValue.Identity );
            var timeScale = new Scale( false, this.Width, new double[] { 0, ConvertValue.HoursPerDay } );

            // Display values.
            double beginOffset = begin.HoursFrom( forecast.Start );
            Scale valueTemplateScale = new Scale( true, this.TemperatureHeight, new double[] { Math.Round( currentTemperature ) } );
            Scale temperatureScale = DisplayTrace( this.TemperatureTrace, this.CurrentTimeMarker, this._temperature, valueTemplateScale, timeScale, beginOffset, hourOffset );

            this.DisplayTemperatureLabels( forecast, units, date, currentTemperature );
            this.DisplayNightBackground( forecast, timeScale, date, begin );
            this.DisplayMidnightLine( mode, timeScale, date, begin );
            DisplayExtremeLine( this.ExtremeLine, this.Width, temperatureScale, units );
        }


        /// <inheritdoc/>
        protected override UIElementCollection ForecastPanelChildren {
            get { return this.ForecastPanel.Children; }
        }


        #region Private Members

        private DataValues _temperature;


        private double TemperatureHeight { get { return this.GraphRow.Height.Value; } }


        private void DisplayTemperatureLabels( Forecast forecast, Units units, DateTimeOffset date, double currentTemperature ) {
            string temperatureUnit = units.GetTemperatureSymbol( );
            this.CurrentTemperatureLabel.Text = string.Format( "{0:0}\u00b0{1}", currentTemperature, temperatureUnit );

            double low, high;
            var extremes = this._temperature.TryGetExtremeValues( forecast.Start, date, minimumCount: 0 );
            if( extremes.TryGetValues( out low, out high ) ) {
                this.LowTemperatureLabel.Text = string.Format( "{0:0}\u00b0", low );
                this.HighTemperatureLabel.Text = string.Format( "{0:0}\u00b0", high );
            }
            else {
                this.LowTemperatureLabel.Text = "";
                this.HighTemperatureLabel.Text = "";
            }
        }

        private void DisplayNightBackground( Forecast forecast, Scale timeScale, DateTimeOffset date, DateTimeOffset begin ) {
            var location = forecast.Location;
            var yesterday = Ephemerides.CalculateDaylight( location, date.AddDays( -1 ) );
            var today = Ephemerides.CalculateDaylight( location, date );
            var tomorrow = Ephemerides.CalculateDaylight( location, date.AddDays( 1 ) );
            double lastNightStart = timeScale.ToScreen( yesterday.Item2.HoursFrom( begin ) );
            double lastNightEnd = timeScale.ToScreen( today.Item1.HoursFrom( begin ) );
            double nightStart = timeScale.ToScreen( today.Item2.HoursFrom( begin ) );
            double nightEnd = timeScale.ToScreen( tomorrow.Item1.HoursFrom( begin ) );

            var clip = (PathGeometry)this.NightBackground.Clip;
            clip.Figures = new PathFigureCollection {
                CreatePathFigure(
                    new Point( lastNightStart, 0 ),
                    new Point( lastNightEnd, 0 ),
                    new Point( lastNightEnd, this.TemperatureHeight ),
                    new Point( lastNightStart, this.TemperatureHeight ) ),
                CreatePathFigure(
                    new Point( nightStart, 0 ),
                    new Point( nightEnd, 0 ),
                    new Point( nightEnd, this.TemperatureHeight ),
                    new Point( nightStart, this.TemperatureHeight ) )
            };
        }

        private void DisplayMidnightLine( ForecastDisplayMode mode, Scale timeScale, DateTimeOffset date, DateTimeOffset begin ) {
            double midnightHour = date.AddDays( 1 ).HoursFrom( begin ) % ConvertValue.HoursPerDay;
            this.MidnightLine.Y2 = this.TemperatureHeight;
            this.MidnightLine.X1 = this.MidnightLine.X2 = timeScale.ToScreen( midnightHour );

            this.MidnightLine.Opacity =
                mode != ForecastDisplayMode.Day
                    ? 1.0
                    : 0.0;
        }

        #endregion

    }

}
